<?php
/**
 * Класс для работы с MVC-ресурсами
 * 
 * @category Phorm
 * @package Mvc
 * @name /Phorm/Mvc.php
 * @copyright phorm.ru
 * @since 21.12.2010
 * @author vladimir@kachalov.net
 */

class Phorm_Mvc extends Phorm_Model {
	
	/**
	 * Возвращает информацию о текущем MVC-ресурсе
	 *  
	 * @return array
	 */
		
	public function getCurrentMvcInfo() {
			
		return $this->getMvcInfo($this->_params);
			
	}
	
	
	/**
	 * Возвращает информацию об MVC-ресурсе на основе параметров
	 * 
	 * @param array $params Массив опций (модуль, контроллер, действие)
	 *  
	 * @return array
	 */
		
	public function getMvcInfo(array $params) {
		
		$select = $this->_db->select()
				-> from('pw_mvc_resources')
				-> where('module=?',$params['module'])
				-> where('controller=?',$params['controller'])
				-> where('action=?',$params['action']);
			
		return $this->_db->fetchRow($select);
			
	}
	
	
	/**
	 * Возвращает информацию об MVC-ресурсе на основе id
	 * 
	 * @param int $resourceid Id ресурса
	 *  
	 * @return array
	 */
		
	public function getMvcInfoById($resourceid) {
		
		$select = $this->_db->select()
				-> from('pw_mvc_resources')
				-> where('resourceid=?',$resourceid);
			
		if($row = $this->_db->fetchRow($select)) {
			
			$select = $this->_db->select()->from('pw_mvc_acl',array('roleid'))->where('resourceid=?',$row['resourceid']);
			
			$row['acl'] = $this->_db->fetchCol($select);
			return $row;
			
		}
		
		return false;
			
	}
	
	
	/**
	 * Возвращает форму добавления/редактирования MVC-ресурса
	 *
	 * @param string $section
	 * @return Zend_Form
	 */
	
	public function getMvcForm($section='add') {
		
		$form = new Phorm_Form('/forms/control/mvc.xml',$section);
		
		$User = new Phorm_User();
		$form->acl->setMultioptions($User->getRolesListAsPairs());
		
		return $form;
		
	}
	
	
	/**
	 * Сохраняет данные об MVC-ресурсе
	 *
	 * @param array $data Массив данных для вставки
	 * @return array
	 */
	
	public function saveMvcInfo($data) {
		
		$maindata = $this->getFilteredValuesByTableCols('pw_mvc_resources',$data);
		unset($maindata['module'],$maindata['controller'],$maindata['action']);
		
		/**
		 * Сохранение данных
		 */
		
		$this->_db->beginTransaction();
		
		try {
			
			// Изменение существующей записи
			
			if(isset($data['resourceid'])) {
				
				$this->_db->update('pw_mvc_resources',$maindata,'resourceid='.(int)$data['resourceid']);
				
			// Вставка новой записи
				
			} else {
				
				$this->_db->insert('pw_mvc_resources',$maindata);
				$data['resourceid'] = $this->_db->lastInsertId();
				
			}
			
			/**
			 * Права доступа
			 */

			$this->_db->delete('pw_mvc_acl','resourceid='.(int)$data['resourceid']);
			
			if(isset($data['acl']) && is_array($data['acl'])) {
				foreach ($data['acl'] as $roleid) {
					$this->_db->insert('pw_mvc_acl',array('resourceid'=>$data['resourceid'],'roleid'=>(int)$roleid));
				}
			}
			
			// Удаляем из таблицы pw_mvc_resources ресурсы для которых не выставлено прав
			//$this->_db->delete('pw_mvc_resources','resourceid NOT IN(SELECT DISTINCT resourceid FROM pw_mvc_acl)');
			
			$this->_db->commit();
										  
			return $data;
			
		} catch (Exception $e) {
			
			$this->_db->rollBack();	
			$this->_errors[] = $e->getMessage();
			
		}
		
		return false;
		
	}
	
	
	/**
	 * Возвращает список ресурсов
	 * 
	 * @return array
	 * @todo Сделать кеширование
	 */
		
	public function getModulesControllersActions() {
			
		$resources = array();
			
		/**
		 * Собираем дерево ресурсов из файловой системы и заносим недостающие в базу
		 */
		
		foreach (scandir(APPLICATION_PATH . '/controllers') as $module) {
			if(is_dir(APPLICATION_PATH . '/controllers/' . $module) && !preg_match('#^\.#',$module)) {
			   	foreach (scandir(APPLICATION_PATH . '/controllers/' . $module) as $controller) {
			   		if(is_file(APPLICATION_PATH . '/controllers/' . $module . '/' . $controller) && !preg_match('#^\.#',$controller)) {
			    		
			   			require_once APPLICATION_PATH . '/controllers/' . $module . '/' . $controller;
			   			$refl = new Zend_Reflection_File(APPLICATION_PATH . '/controllers/' . $module . '/' . $controller);
			   			$classes = $refl->getClasses();
			   			
			   			foreach ($classes as $class) {
			   				
			   				$classname = $class->getName();
			   				$controller = strtolower(str_replace('Controller.php','',$controller));
			   				
			   				$comment = $class->getDocComment();
			   				if($comment!='') {
			   					$dbl = new Zend_Reflection_Docblock($comment);
			   					$resources[$module]['controllers'][$controller]['resourcename'] = $dbl->getShortDescription();
			   				}
			   				
			   				foreach ($class->getMethods() as $method) {
			   					if(!preg_match('#Action$#',$method->getName())) continue;
			   					$action = preg_replace('#Action$#','',$method->getName());
			   					$comment = $method->getDocComment();
			   					if($comment!='') {
			   						$dbl = new Zend_Reflection_Docblock($comment);
			   						$comment = $dbl->getShortDescription();
			   					}
			   					$data = array(
			   						'module' => $module,
			   						'controller' => $controller,
			   						'action' => $action,
			   						'resourcename' => $comment
			   					);
			   					if($info = $this->getMvcInfo($data)) {
			   						$resources[$module]['controllers'][$controller]['actions'][$action] = $info;
			   					} else {
			   						if($this->_db->insert('pw_mvc_resources',$data)){
			   							$data['resourceid'] = $this->_db->lastInsertId();
			   							$resources[$module]['controllers'][$controller]['actions'][$action] = $data;
			   						}
			   					}
			   				}
			   			}
			    	}
			    }
			}
		}
			
		return $resources;
			
	}
	
	
	/**
	 * Возвращает объект меню MVC-компонент для контрольной панели
	 *
	 * @return Zend_Navigation
	 */
	
	public function getNavigationMenu() {
		
		$Tree = $this->getModulesControllersActions();
		
		// Модули
		
		foreach ($Tree as $modulename=>$module) {
			
			$Tree[$modulename] = array(
				'label' => $modulename == 'control'
							? $this->_translate->_('Административная панель') . ' (' . $modulename . ')'
							: $this->_translate->_('Сайт') . ' (' . $modulename . ')',
				'uri' => '#',
				'pages' => array()
			);
			
			// Контроллеры
			
			foreach ($module['controllers'] as $controllername=>$controller) {
				
				$Tree[$modulename]['pages'][$controllername] = array(
					'label' => empty($controller['resourcename']) ? $controllername : $controller['resourcename'],
					'uri' => '#',
					'pages' => array()
				);
				
				// Действия
				
				foreach ($controller['actions'] as $actionname=>$action) {
					
					$Tree[$modulename]['pages'][$controllername]['pages'][$actionname] = array(
						'label' => empty($action['resourcename']) ? $actionname : $action['resourcename'],
						'id' => $action['resourceid'],
						'uri' => '/control/mvc/edit/resourceid/' . $action['resourceid'] . '/',
						'target' => 'CenterFrame'
					);
					
				}
				
			}
			
		}
		
		return new Zend_Navigation($Tree);
		
	}
	
	
	/**
	 * Возвращает ACL-таблицу MVC-компонент для матрицы
	 * 
	 * @return array
	 */
		
	public function getAclList() {
		
		$select = $this->_db->select()
				->from('pw_mvc_acl')
				->order('roleid');
				
		$out = array();
			
		if($rows = $this->_db->fetchAll($select)) {
			foreach ($rows as $row) {
				$out[$row['roleid']][$row['resourceid']] = $row['resourceid'];
			}
			return $out;
		}
		
		return false;
			
	}
	
	
	/**
	 * Обновляет связку ресурсов с ролями
	 * 
	 * @return boolean
	 */
		
	public function updateRolesAcl(array $data = array()) {
			
		$sqlarr = array();
			
		foreach ($data as $roleid=>$resources) {
			foreach ($resources as $resourceid) {
				if($resourceid>0 && $roleid>0) {
					$sqlarr[] = array('roleid'=>$roleid,'resourceid'=>$resourceid);
				}
			}
		}
		
		$this->_db->beginTransaction();
		
		try {
			
			$this->_db->query('TRUNCATE TABLE pw_mvc_acl');
			foreach ($sqlarr as $arr) $this->_db->insert('pw_mvc_acl',$arr);
			
			// Удаляем из таблицы pw_mvc_resources ресурсы для которых не выставлено прав
			$this->_db->delete('pw_mvc_resources','resourceid NOT IN(SELECT DISTINCT resourceid FROM pw_mvc_acl)');
			
			$this->_db->commit();
			return true;
		
		} catch (Exception $e) {
			
			$this->_db->rollBack();
			$this->_errors[] = $e->getMessage();
			
		}
		
		return false;
			
	}	
	
}
